﻿/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.Collections.Generic;
using System.Net;

#if SILVERLIGHT
using System.Windows.Browser;
#endif

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using QUT.Bio.SilverMap.MapService;

/*

System.Windows.Browser.HtmlPage.Window.Eval( "location.toString()" )
"http://localhost:2667/SilverMap.Web/SilverMapBetaTestPage.html?test=1&test2=2"

 */

namespace QUT.Bio.SilverMap {
	public static class Args {
		private static readonly string [] standardArguments = {
			"AutoLoad: True or False. Whether to load from web service automatically.",
			"MapWebService: 'null' or a valid web service url. If 'null', data will not be obtained from web service. If omitted, a default web service will be used.",
			"DistanceType: EValue, Positives or Identities (for web service query).",
			"Cutoff: The numeric threshold for arcs (for web service query).",
			"ReferenceGene: the numeric id of the current reference gene. For auto load from web service.",
			"Subjects: a list of accession codes for subject sequences. For auto load from web service.",
			"Selected: a list of numeric ids for selected genes. For auto load from web service.",
			"UseTags: True or False. Whether to make tag functions active.",
			"TagWebService: 'null' or a valid web service url for tag functions."
		};

		/// <summary>
		/// Gets a list of arguments understood by the 
		/// </summary>
		public static string [] StandardArguments {
			get {
				return standardArguments;
			}
		}
		
		/// <summary>
		/// A delegate type used to process arguments.
		/// </summary>
		/// <param name="model"></param>
		/// <param name="view"></param>
		/// <param name="name"></param>
		/// <param name="value"></param>
		public delegate void Processor ( ViewModel model, View view, string name, string value );
		
		private	static readonly Dictionary<string, Processor> proc = new Dictionary<string, Processor>{
				{"AutoLoad", ProcessAutoLoad},
				{"Cutoff", ProcessCutoff},
				{"DistanceType", ProcessDistanceType},
				{"ReferenceGene", ProcessReferenceGene},
				{"Selected", ProcessSelected},
				{"Subjects", ProcessSubjects},
				{"MapWebService", ProcessMapWebService},
				{"TagWebService", ProcessTagWebService},
				{"UseTags", ProcessUseTags}
			};
		
		/// <summary>
		/// Gets a reference to the jump table used to process arguments.
		/// <para>Applications can can add or remove entries as required to suit their purposes.</para>
		/// </summary>
		public static Dictionary<string, Processor> JumpTable {
			get {
				return proc;
			}
		}

		/// <summary>
		/// Process command line arugments / initParams / html query parameters.
		/// </summary>		 
		public static void Process ( ViewModel model, View view, IDictionary<string, string> initParams ) {
			MergeQueryArguments( initParams );

			foreach ( KeyValuePair<string, string> p in initParams ) {
				string name = p.Key;
				string value = p.Value;

				if ( proc.ContainsKey( name ) ) {
					proc[name]( model, view, name, value );
				}
			}
		}

		// Adds html query parameters to the initparams.
		private static void MergeQueryArguments ( IDictionary<string, string> initParams ) {
#if SILVERLIGHT
			foreach ( var x in HtmlPage.Document.QueryString ) {
				initParams[x.Key] = x.Value;
			}
#endif
		}

		private static void ProcessSubjects( ViewModel model, View view, string name, string value ) {
			model.Subjects = value.Split( ';' );
		}

		private static void ProcessSelected( ViewModel model, View view, string name, string value ) {
			string [] t = value.Split( ';' );
			List<decimal> ids = new List<decimal>();

			foreach ( string s in t ) {
				try {
					ids.Add( decimal.Parse( s ) );
				}
				catch { }
			}

			if ( ids.Count > 0 ) {
				model.SelectedGeneIds = ids.ToArray();
			}
		}

		private static void ProcessReferenceGene( ViewModel model, View view, string name, string value ) {
			decimal referenceGeneId;

			if ( decimal.TryParse( value, out referenceGeneId ) ) {
				model.ReferenceGeneId = referenceGeneId;
				model.LoadReferenceGene();
			}
			else {
				view.Overlay.Alert( "Invalid argument: {0} should be a numeric value but I found '{1}']", name, value );
			}
		}

		private static void ProcessCutoff( ViewModel model, View view, string name, string value ) {
			double cutoff;

			if ( double.TryParse( value, out cutoff ) ) {
				if ( cutoff <= 0 ) {
					view.Overlay.Alert( "Invalid argument: {0} should be greater than 0, but I found '{1}'", name, cutoff );
				}
				else {
					model.Cutoff = cutoff;
					model.Normalizer.UpperBound = cutoff;
				}
			}
			else {
				view.Overlay.Alert( "Invalid argument: {0} should be a numeric value but I found '{1}']", name, value );
			}
		}

		private static void ProcessDistanceType( ViewModel model, View view, string name, string value ) {
			try {
				model.DistanceType = (DistanceType) Enum.Parse( typeof( DistanceType ), value, true );
			}
			catch {
				view.Overlay.Alert( "Invalid argument: {0} should be one of ({2}) but I found '{1}']", name, value, string.Join( ",", DataLayer.ListAvailableDistanceTypes() ) );
			}
		}

		private static void ProcessAutoLoad( ViewModel model, View view, string name, string value ) {
			try {
				model.AutoLoad = bool.Parse( value );
			}
			catch {
				view.Overlay.Alert( "Invalid argument: {0} should be 'True' or 'False' but I found '{1}']", name, value );
			}
		}

		private static void ProcessMapWebService( ViewModel model, View view, string name, string value ) {
			model.DataLayer = value == "null" 
			? null 
			: new DataLayer( model, view, value );
		}

		private static void ProcessUseTags( ViewModel model, View view, string name, string value ) {
			try {
				model.TagsEnabled = bool.Parse( value );
				
				if ( model.TagsEnabled ) {
					TagModule.Tags.CreateProgressWindow = view.CreateInfoWindow;
				}
			}
			catch {
				view.Overlay.Alert( "Invalid argument: {0} should be 'True' or 'False' but I found '{1}']", name, value );
			}
		}

		private static void ProcessTagWebService( ViewModel model, View view, string name, string value ) {
			TagModule.Tags.WebServiceAddress = value;
		}
	}
}
